package com.yanqu.road.server.manager.cross.battle.ghost;

import com.yanqu.road.dao.impl.activity.ghost.GhostUserAbilityDaoImpl;
import com.yanqu.road.entity.activity.ActivityConfig;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.ghost.*;
import com.yanqu.road.entity.activity.ghost.config.GhostBossConfig;
import com.yanqu.road.entity.activity.ghost.config.GhostBoxConfig;
import com.yanqu.road.entity.activity.ghost.config.GhostConfig;
import com.yanqu.road.entity.activity.ghost.config.GhostDisperseConfig;
import com.yanqu.road.entity.activity.ghost.config.GhostGuessConfig;
import com.yanqu.road.entity.activity.huashigang.HuaShiGangUserData;
import com.yanqu.road.entity.enums.eActivityConfigType;
import com.yanqu.road.entity.log.LogGhostYuanBing;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.entity.rank.cross.CrossUserRank;
import com.yanqu.road.entity.servercenter.ServerInfo;
import com.yanqu.road.logic.bussiness.activity.GhostActivityBusiness;
import com.yanqu.road.logic.bussiness.log.LogBussiness;
import com.yanqu.road.logic.bussiness.servercenter.ActivityBussiness;
import com.yanqu.road.logic.bussiness.servercenter.ServerBussiness;
import com.yanqu.road.logic.cross.CrossActivityRankListModel;
import com.yanqu.road.logic.helper.ActivityHelper;
import com.yanqu.road.logic.pb.GhostPb;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.server.manager.log.CrossAutoLogMgr;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.pb.activity.GhostActivityProto;
import com.yanqu.road.pb.player.PlayerProto;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.GameProtocol;
import com.yanqu.road.utils.LocalDateTimeHelper;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

public class GhostActivity {

    private final Logger logger = LogManager.getLogger(GhostActivity.class);


    private final Object lockObject = new Object();
    // 所有配置
    private GhostConfig ghostConfig;
    // 数据
    private GhostData ghostData;
    // Boss伤害榜单（不入库），Map<BossId，榜单>
    private Map<Integer, CrossActivityRankListModel> damageRankListMap = new ConcurrentHashMap<>();


    // 玩家操作锁
    private final Object lockActionObject = new Object();
    // 玩家操作数据
    private LinkedList<GhostActivityProto.GhostPlayerActionMsg> actionMsgList = new LinkedList<>();
    // boss房间数据（不入库）
    private GhostCrossSceneLogic sceneLogic = new GhostCrossSceneLogic();

    //玩家门客总赚钱明细Map, k:区服id，v:玩家门客总赚钱list
    private Map<Long, Map<Long, GhostUserAbility>> userAbilityMap = new ConcurrentHashMap<>();

    public GhostActivity(ActivityInfo activityInfo) {
        reloadConfig(activityInfo);
        // 读取跨服数据
        ghostData = GhostActivityBusiness.getGhostData(activityInfo.getActivityId());
        initGhostData(activityInfo.getActivityId());

        // 读取最新批次boss
        Map<Integer, Map<Integer, GhostBossData>> batchBossMap = GhostActivityBusiness.getGhostBossDataMap(activityInfo.getActivityId(), ghostData.getMaxBatchNo());
        checkBossMap(batchBossMap); // 检查下类型是否完整，否则按类型遍历报错
        ghostData.getBossMap().put(ghostData.getMaxBatchNo(), batchBossMap);
        // 设置下个bossId
        Integer maxBossId = GhostActivityBusiness.getGhostMaxBossId(activityInfo.getActivityId());
        ghostData.setNextBossId(maxBossId == null ? new AtomicInteger(1) : new AtomicInteger(maxBossId + 1));

        // 读取最新批次的送财
        Map<Integer, List<GhostDisperseData>> ghostDisperseDataMap = GhostActivityBusiness.getGhostDisperseDataMap(activityInfo.getActivityId(), ghostData.getMaxBatchNo());
        ghostData.getDisperseMap().put(ghostData.getMaxBatchNo(), ghostDisperseDataMap);
        // 设置下个送财Id
        Integer maxDisperseId = GhostActivityBusiness.getGhostMaxDisperseId(activityInfo.getActivityId());
        ghostData.setNextDisperseId(maxDisperseId == null ? new AtomicInteger(1) : new AtomicInteger(maxDisperseId + 1));

        // 读取最新批次情报
        Map<String, Map<Integer, List<GhostUnionNews>>> unionNewsMap = GhostActivityBusiness.getGhostUnionNewsMap(activityInfo.getActivityId(), ghostData.getMaxBatchNo());
        ghostData.getUnionNewsMap().put(ghostData.getMaxBatchNo(), unionNewsMap);
        // 设置下个Id
        Integer maxNewsId = GhostActivityBusiness.getGhostMaxNewsId(activityInfo.getActivityId());
        ghostData.setNextNewsId(maxNewsId == null ? new AtomicInteger(1) : new AtomicInteger(maxNewsId + 1));

        // 读取最新批次boss攻击记录
        Map<Integer, Map<Long, GhostAttackRecord>> ghostAttackRecordMap = GhostActivityBusiness.getGhostAttackRecordMap(activityInfo.getActivityId(), ghostData.getMaxBatchNo());
        ghostData.getAttackRecordMap().put(ghostData.getMaxBatchNo(), ghostAttackRecordMap);
        cleanOldAttackRecordMap();

        // 生成榜单
        initRankListModel();

        // 读取送财人员
        Map<Integer, Map<Integer, GhostDispersePlayer>> dispersePlayerMap = GhostActivityBusiness.getGhostDispersePlayerMap(activityInfo.getActivityId());
        ghostData.setDispersePlayerMap(dispersePlayerMap);

        //6.5.0 玩家最高赚钱信息
        this.userAbilityMap = new GhostUserAbilityDaoImpl().getGhostUserAbilityData(activityInfo.getActivityId());

        // 初始化今日数据
        initTodayCount();
    }

    public ActivityInfo getActivityInfo(){
        return ghostConfig.getActivityInfo();
    }

    public void save() {

        if (ghostData.isInsertOption()) {
            GhostActivityBusiness.addGhostData(ghostData);
        } else if (ghostData.isUpdateOption()) {
            GhostActivityBusiness.updateGhostData(ghostData);
        }

        for (Map<Integer, Map<Integer, GhostBossData>> value : ghostData.getBossMap().values()) {
            for (Map<Integer, GhostBossData> bossDataMap : value.values()) {
                for (GhostBossData bossData : bossDataMap.values()) {
                    if (bossData.isInsertOption()) {
                        GhostActivityBusiness.addGhostBossData(bossData);
                    } else if (bossData.isUpdateOption()) {
                        GhostActivityBusiness.updateGhostBossData(bossData);
                    }
                }
            }
        }

        for (Map<Integer, List<GhostDisperseData>> listMap : ghostData.getDisperseMap().values()) {
            for (List<GhostDisperseData> dataList : listMap.values()) {
                for (int i = 0; i < dataList.size(); i++) {
                    GhostDisperseData disperseData = dataList.get(i);
                    if (disperseData.isInsertOption()) {
                        GhostActivityBusiness.addGhostDisperseData(disperseData);
                    } else if (disperseData.isUpdateOption()) {
                        GhostActivityBusiness.updateGhostDisperseData(disperseData);
                    }
                }
            }
        }

        for (Map<String, Map<Integer, List<GhostUnionNews>>> mapMap : ghostData.getUnionNewsMap().values()) {
            for (Map<Integer, List<GhostUnionNews>> listMap : mapMap.values()) {
                for (List<GhostUnionNews> unionNewsList : listMap.values()) {
                    for (int i = 0; i < unionNewsList.size(); i++) {
                        GhostUnionNews unionNews = unionNewsList.get(i);
                        if (unionNews.isInsertOption()) {
                            GhostActivityBusiness.addGhostUnionNews(unionNews);
                        } else if (unionNews.isUpdateOption()) {
                            GhostActivityBusiness.updateGhostUnionNews(unionNews);
                        }
                    }
                }
            }
        }

        for (Map<Integer, Map<Long, GhostAttackRecord>> mapMap : ghostData.getAttackRecordMap().values()) {
            for (Map<Long, GhostAttackRecord> recordMap : mapMap.values()) {
                for (GhostAttackRecord record : recordMap.values()) {
                    if (record.isInsertOption()) {
                        GhostActivityBusiness.addGhostAttackRecord(record);
                    } else if (record.isUpdateOption()) {
                        GhostActivityBusiness.updateGhostAttackRecord(record);
                    }
                }
            }
        }

        for (Map<Integer, GhostDispersePlayer> playerMap : ghostData.getDispersePlayerMap().values()) {
            for (GhostDispersePlayer dispersePlayer : playerMap.values()) {
                if (dispersePlayer.isInsertOption()) {
                    GhostActivityBusiness.addGhostDispersePlayer(dispersePlayer);
                } else if (dispersePlayer.isUpdateOption()) {
                    GhostActivityBusiness.updateGhostDispersePlayer(dispersePlayer);
                }
            }
        }

        //6.5.0 玩家最高赚钱信息
        GhostUserAbilityDaoImpl ghostUserAbilityDao = new GhostUserAbilityDaoImpl();
        for (Map<Long, GhostUserAbility> map : this.userAbilityMap.values()) {
            for (GhostUserAbility ghostUserAbility : map.values()) {
                if (ghostUserAbility.isInsertOption()) {
                    ghostUserAbilityDao.add(ghostUserAbility);
                }
            }
        }

        // 清空旧批次数据
        List<Integer> batchNoList = new ArrayList<>();
        int maxNo = ghostData.getMaxBatchNo();
        for (Map.Entry<Integer, Map<Integer, Map<Integer, GhostBossData>>> entry : ghostData.getBossMap().entrySet()) {
            if (entry.getKey() != maxNo) {
                batchNoList.add(entry.getKey());
            }
        }
        for (Integer batchNo : batchNoList) {
            ghostData.getBossMap().remove(batchNo);
            ghostData.getDisperseMap().remove(batchNo);
            ghostData.getUnionNewsMap().remove(batchNo);
            ghostData.getAttackRecordMap().remove(batchNo);
            // 送财人员就不清了，量极少
        }
    }

    public void repair() {

    }

    public void reloadConfig(ActivityInfo activityInfo) {
        synchronized (lockObject) {
            logger.info("reload Ghost Activity start");

            int activityId = activityInfo.getActivityId();
            List<Integer> activityIdList = new ArrayList<>();
            activityIdList.add(activityId);

            GhostConfig tmpConfig = new GhostConfig();
            tmpConfig.setActivityId(activityId);
            tmpConfig.setActivityInfo(activityInfo);

            // boss配置
            List<GhostBossConfig> bossConfigList = GhostActivityBusiness.getGhostBossConfigList(activityId);
            tmpConfig.setBossConfigList(bossConfigList);

            // 其他配置
            Map<String, ActivityConfig> activityConfigMap = ActivityBussiness.getActivityConfigMap(activityIdList).get(activityId);

            String energyConfig = activityConfigMap.get(eActivityConfigType.GHOST_ENERGY_PARAM.getName()).getValue();
            tmpConfig.setMaxEnergy(Integer.valueOf(energyConfig.split(";")[0]));
            tmpConfig.setEnergyRecoveryTime(1000 * Long.valueOf(energyConfig.split(";")[1]));

            List<Integer> buyEnergyConfig = activityConfigMap.get(eActivityConfigType.GHOST_ENERGY_BUY_PARAM.getName()).getIntListValue(";");
            tmpConfig.setBuyEnergyBaseIngots(buyEnergyConfig.get(0));
            tmpConfig.setBuyEnergyIncrIngots(buyEnergyConfig.get(1));
            tmpConfig.setBuyEnergyGetCount(buyEnergyConfig.get(2));
            tmpConfig.setOnceEnergyBuyTimes(buyEnergyConfig.get(3));

            tmpConfig.setExploreGetTokenCount(activityConfigMap.get(eActivityConfigType.GHOST_EXPLORE_GET_TOKEN_COUNT.getName()).getIntValue());

            List<Integer> newsConfig = activityConfigMap.get(eActivityConfigType.GHOST_UNION_NEWS_COUNT.getName()).getIntListValue(";");
            tmpConfig.setMaxAliveNewsCount(newsConfig.get(0));
            tmpConfig.setMaxDeadNewsCount(newsConfig.get(1));

            tmpConfig.setEventWeightList(activityConfigMap.get(eActivityConfigType.GHOST_EVENT_WEIGHT_PARAM.getName()).getIntListValue(";"));

            tmpConfig.setFreeAttackTimes(activityConfigMap.get(eActivityConfigType.GHOST_FREE_ATTACK_TIMES.getName()).getIntValue());

            tmpConfig.setFreeAttackGetTokenCount(activityConfigMap.get(eActivityConfigType.GHOST_FREE_ATTACK_GET_TOKEN_COUNT.getName()).getIntValue());

            tmpConfig.setAttackCostItemCountList(activityConfigMap.get(eActivityConfigType.GHOST_ATTACK_COST_ITEM_COUNT.getName()).getIntListValue(";"));

            tmpConfig.setAttackCostItemId(activityConfigMap.get(eActivityConfigType.GHOST_ATTACK_COST_ITEM_ID.getName()).getIntValue());

            tmpConfig.setAttackCostToTokenCoefficient(activityConfigMap.get(eActivityConfigType.GHOST_ATTACK_COST_TO_TOKEN_COEFFICIENT.getName()).getIntValue());

            tmpConfig.setDamageToScoreRatioList(activityConfigMap.get(eActivityConfigType.GHOST_DAMAGE_SCORE_COEFFICIENT.getName()).getIntListValue("\\|"));

            tmpConfig.setBigBossFindReward(activityConfigMap.get(eActivityConfigType.GHOST_BIG_BOSS_FIND_REWARD.getName()).getValue());

            String disperseConfigParam = activityConfigMap.get(eActivityConfigType.GHOST_DISPERSE_REWARD_PARAM.getName()).getValue();
            List<GhostDisperseConfig> disperseConfigList = new ArrayList<>();
            for (String item : StringUtils.stringToStringList(disperseConfigParam, "\\|")) {
                List<String> paramList = StringUtils.stringToStringList(item, ";");
                GhostDisperseConfig disperseConfig = new GhostDisperseConfig();
                disperseConfig.setReward(paramList.get(0));
                disperseConfig.setCount(Integer.valueOf(paramList.get(1)));
                disperseConfig.setWeight(Integer.valueOf(paramList.get(2)));
                disperseConfig.setNotice(Integer.valueOf(paramList.get(3)) == 1);
                disperseConfigList.add(disperseConfig);
            }
            tmpConfig.setDisperseConfigList(disperseConfigList);

            tmpConfig.setDisperseBaseReward(activityConfigMap.get(eActivityConfigType.GHOST_DISPERSE_BASE_REWARD.getName()).getValue());

            String boxConfigParam = activityConfigMap.get(eActivityConfigType.GHOST_BOX_PARAM.getName()).getValue();
            List<GhostBoxConfig> boxConfigList = new ArrayList<>();
            for (String item : StringUtils.stringToStringList(boxConfigParam, "\\|")) {
                List<Integer> paramList = StringUtils.stringToIntegerList(item, ";");
                GhostBoxConfig boxConfig = new GhostBoxConfig();
                boxConfig.setBoxItemId(paramList.get(0));
                boxConfig.setWeight(paramList.get(1));
                boxConfig.setOpenCost(paramList.get(2) == 0 ? "0" : paramList.get(2) + "=1");
                boxConfigList.add(boxConfig);
            }
            tmpConfig.setBoxConfigList(boxConfigList);

            tmpConfig.setGuessCost(activityConfigMap.get(eActivityConfigType.GHOST_GUESS_COST.getName()).getValue());

            List<GhostGuessConfig> guessConfigList = new ArrayList<>();
            String guessConfigParam = activityConfigMap.get(eActivityConfigType.GHOST_GUESS_PARAM.getName()).getValue();
            for (String item : StringUtils.stringToStringList(guessConfigParam, "\\|")) {
                List<Integer> paramList = StringUtils.stringToIntegerList(item, ";");
                GhostGuessConfig guessConfig = new GhostGuessConfig();
                guessConfig.setRealReward(paramList.get(0) + "=1");
                guessConfig.setFakeReward(paramList.get(1) + "=1");
                guessConfigList.add(guessConfig);
            }
            tmpConfig.setGuessConfigList(guessConfigList);

            tmpConfig.setGuessRealRatio(activityConfigMap.get(eActivityConfigType.GHOST_GUESS_REAL_RATIO.getName()).getIntValue());

            tmpConfig.setGuessNpcId(activityConfigMap.get(eActivityConfigType.GHOST_MARKET_GUESS_NPC_ID.getName()).getIntValue());

            tmpConfig.setAttackBuffId(activityConfigMap.get(eActivityConfigType.GHOST_ATTACK_BUFF_ID.getName()).getIntValue());

            tmpConfig.setTokenId(activityConfigMap.get(eActivityConfigType.GHOST_TOKEN_ID.getName()).getIntValue());

            tmpConfig.setScoreId(activityConfigMap.get(eActivityConfigType.GHOST_SCORE_ID.getName()).getIntValue());

            List<Integer> operationTime = activityConfigMap.get(eActivityConfigType.GHOST_OPERATION_TIME_PARAM.getName()).getIntListValue(";");
            tmpConfig.setStartOperationTime(60 * 1000 * operationTime.get(0));
            tmpConfig.setEndOperationTime(60 * 1000 * operationTime.get(1));

            List<Integer> dayList = new ArrayList<>();
            List<Integer> valueList = new ArrayList<>();
            String hpDayParam = activityConfigMap.get(eActivityConfigType.GHOST_HP_DAY_PARAM.getName()).getValue();
            for (String item : StringUtils.stringToStringList(hpDayParam, "\\|")) {
                List<Integer> paramList = StringUtils.stringToIntegerList(item, ";");
                dayList.add(paramList.get(0));
                valueList.add(paramList.get(1));
            }
            tmpConfig.setHpDayList(dayList);
            tmpConfig.setHpValueList(valueList);

            String abilityEnlargeStr = activityConfigMap.get(eActivityConfigType.GHOST_ABILITY_ENLARGE.getName()).getValue();
            String[] arr = abilityEnlargeStr.split("\\|");
            Map<Integer, Integer> abilityEnlargeMap = new HashMap<>();
            for (String s : arr) {
                String[] split = s.split(";");
                if (split.length >= 2) {
                    int key = Integer.parseInt(split[0]);
                    int value = Integer.parseInt(split[1]);
                    abilityEnlargeMap.put(key, value);
                } else if (split.length == 1) {
                    abilityEnlargeMap.put(0, Integer.parseInt(split[0]));
                }
            }
            tmpConfig.setAbilityEnlargeMap(abilityEnlargeMap);

            tmpConfig.setDisperseBaseReward2(activityConfigMap.get(eActivityConfigType.GHOST_CLEAN_DISPERSE_BASE_REWARD.getName()).getValue());

            tmpConfig.setFinalKillReward(activityConfigMap.get(eActivityConfigType.GHOST_FINAL_KILL_DISPERSE_REWARD.getName()).getValue());

            String cleanDisperseParam = activityConfigMap.get(eActivityConfigType.GHOST_CLEAN_DISPERSE_REWARD_PARAM.getName()).getValue();
            List<GhostDisperseConfig> tmpList = new ArrayList<>();
            for (String item : StringUtils.stringToStringList(cleanDisperseParam, "\\|")) {
                List<String> paramList = StringUtils.stringToStringList(item, ";");
                GhostDisperseConfig disperseConfig = new GhostDisperseConfig();
                disperseConfig.setReward(paramList.get(0));
                disperseConfig.setCount(Integer.valueOf(paramList.get(1)));
                disperseConfig.setWeight(Integer.valueOf(paramList.get(2)));
                disperseConfig.setNotice(Integer.valueOf(paramList.get(3)) == 1);
                tmpList.add(disperseConfig);
            }
            tmpConfig.setDisperseConfigList2(tmpList);

            tmpConfig.setAttackBuffSwitch(activityConfigMap.get(eActivityConfigType.GHOST_ATTACK_BUFF_SWITCH.getName()).getIntValue());

            tmpConfig.setBigBossStageCount(activityConfigMap.get(eActivityConfigType.GHOST_BIG_BOSS_STAGE_COUNT.getName()).getIntValue());

            List<String> rewardList = new ArrayList<>();
            List<Integer> weightList = new ArrayList<>();
            String stageRewardParam = activityConfigMap.get(eActivityConfigType.GHOST_BIG_BOSS_STAGE_REWARD_PARAM.getName()).getValue();
            for (String item : StringUtils.stringToStringList(stageRewardParam, "\\|")) {
                List<String> stringList = StringUtils.stringToStringList(item, ",");
                rewardList.add(stringList.get(0));
                weightList.add(Integer.valueOf(stringList.get(1)));
            }
            tmpConfig.setBigBossStageRewardList(rewardList);
            tmpConfig.setBigBossStageWeightLis(weightList);

            tmpConfig.setBigBossStageScoreParam(activityConfigMap.get(eActivityConfigType.GHOST_BIG_BOSS_STAGE_REWARD_SCORE_PARAM.getName()).getIntValue());

            List<Integer> yuanBingParam = activityConfigMap.get(eActivityConfigType.GHOST_YUAN_BING_TRIGGER_PARAM.getName()).getIntListValue(";");
            tmpConfig.setYuanBingTriggerEndTime(yuanBingParam.get(0) * 60L * 1000L);
            tmpConfig.setYuanBingTriggerHpPercent(yuanBingParam.get(1));

            String yuanBingCountParam = activityConfigMap.get(eActivityConfigType.GHOST_YUAN_BING_COUNT_PARAM.getName()).getValue();
            List<Integer> typeList = new ArrayList<>();
            List<Integer> countList = new ArrayList<>();
            for (String item : StringUtils.stringToStringList(yuanBingCountParam, ";")) {
                List<Integer> param = StringUtils.stringToIntegerList(item, ",");
                typeList.add(param.get(0));
                countList.add(param.get(1));
            }
            tmpConfig.setYuanBingBossTypeList(typeList);
            tmpConfig.setYuanBingBossCountList(countList);

            List<Integer> refreshParam = activityConfigMap.get(eActivityConfigType.GHOST_REFRESH_TIME_PARAM.getName()).getIntListValue(";");
            List<Long> refreshTimeList = new ArrayList<>();
            for (Integer refreshTime : refreshParam) {
                refreshTimeList.add(refreshTime * 60L * 1000L);
            }
            tmpConfig.setRefreshTimeList(refreshTimeList);

            List<Integer> scoreDayList = new ArrayList<>();
            List<Integer> scoreValueList = new ArrayList<>();
            String scoreDayParam = activityConfigMap.get(eActivityConfigType.GHOST_SCORE_DAY_PARAM.getName()).getValue();
            for (String item : StringUtils.stringToStringList(scoreDayParam, "\\|")) {
                List<Integer> paramList = StringUtils.stringToIntegerList(item, ";");
                scoreDayList.add(paramList.get(0));
                scoreValueList.add(paramList.get(1));
            }
            tmpConfig.setScoreDayList(scoreDayList);
            tmpConfig.setScoreValueList(scoreValueList);

            if (activityConfigMap.containsKey(eActivityConfigType.GHOST_SEARCH_BIG_BOSS_PARAM.getName())) {
                List<Integer> searchBigBossList = activityConfigMap.get(eActivityConfigType.GHOST_SEARCH_BIG_BOSS_PARAM.getName()).getIntListValue(";");
                if (searchBigBossList.get(0) <= 0) {
                    throw new RuntimeException("鬼市探索活阎王增加权重的配置有问题 activityId" + activityId);
                }
                tmpConfig.setBigBossAddiTimes(searchBigBossList.get(0));
                tmpConfig.setBigBossAddiWeight(searchBigBossList.get(1));
            }
            //v5.5 自动战斗配置
            if (activityConfigMap.containsKey(eActivityConfigType.GHOST_AUTO_BATTLE.getName())) {
                tmpConfig.setAutoBattleLimit(activityConfigMap.get(eActivityConfigType.GHOST_AUTO_BATTLE.getName()).getIntValue());
            } else {
                tmpConfig.setAutoBattleLimit(20);
            }

            //6.5.0 boss血量参数
            String hpParam1 = ActivityHelper.getActivityConfigValue(activityConfigMap, eActivityConfigType.GHOST_BOSS_HP_PARAM_1);
            tmpConfig.setBossHpParam1(StringUtils.stringToIntegerList(hpParam1, "\\|"));
            String hpParam2 = ActivityHelper.getActivityConfigValue(activityConfigMap, eActivityConfigType.GHOST_BOSS_HP_PARAM_2);
            List<List<Integer>> bossHpEnlargeParam = new ArrayList<>();
            for (String str : StringUtils.stringToStringList(hpParam2, "#")) {
                bossHpEnlargeParam.add(StringUtils.stringToIntegerList(str, "\\|"));
            }
            tmpConfig.setBossHpParam2(bossHpEnlargeParam);

            ghostConfig = tmpConfig;

            logger.info("reload Ghost Activity finish");
        }
    }

    public GhostConfig getGhostConfig() {
        return ghostConfig;
    }

    public GhostData getGhostData() {
        return ghostData;
    }

    private void initGhostData(int activityId) {
        if (ghostData == null) {
            GhostData tmpGhostData = new GhostData();
            tmpGhostData.setActivityId(activityId);
            tmpGhostData.setLastResetTime(0);
            tmpGhostData.setMaxBatchNo(0);
            tmpGhostData.setAbilityMap(new ConcurrentHashMap<>());
            tmpGhostData.setAvgAbility(0);
            tmpGhostData.setAvgOpenDay(0);
            tmpGhostData.setInsertOption();
            ghostData = tmpGhostData;
        }
    }

    /**
     * 注入玩家门客总赚钱MAP
     * @param serverId 区服ID
     * @param userAbilityList 玩家门客总赚钱LIST
     */
    public void addUserAbilityList(long serverId, List<GhostActivityProto.UserAbilityItem> userAbilityList) {
        Map<Long, GhostUserAbility> map = this.userAbilityMap.computeIfAbsent(serverId, k -> new ConcurrentHashMap<>());
        for (GhostActivityProto.UserAbilityItem item : userAbilityList) {
            if (!map.containsKey(item.getUserId())) {
                GhostUserAbility ghostUserAbility = new GhostUserAbility(this.ghostConfig.getActivityId(), serverId, item.getUserId(), item.getUserAbility());
                map.put(item.getUserId(), ghostUserAbility);
            }
        }
    }

    /**
     * 生成boss
     *
     * @return BossMap <类型 ， ID ， 数据>
     */
    private Map<Integer, Map<Integer, GhostBossData>> createBatchBoss(int batchNo) {

        // 获取赚钱
        long avgAbility = ghostData.getAvgAbility();
        if (avgAbility <= 0) {
            // 平均赚钱 = 区服平均 + 区服平均 + 区服平均
            BigDecimal tmpAvgAbility = BigDecimal.ZERO;
            for (List<Long> value : ghostData.getAbilityMap().values()) {
                int dayCount = 0;
                BigDecimal tmp = BigDecimal.ZERO;
                for (Long ability : value) {
                    tmp = tmp.add(new BigDecimal(ability));
                    dayCount++;
                }
                if (dayCount > 0) {
                    tmpAvgAbility = tmpAvgAbility.add(tmp.divide(BigDecimal.valueOf(dayCount), 0, BigDecimal.ROUND_UP));
                }
            }

            avgAbility = tmpAvgAbility.longValue();
            ghostData.setAvgAbility(avgAbility);
        }
        // 获取开服天数
        int avgOpenDay = ghostData.getAvgOpenDay();

        if (avgOpenDay <= 0) {
            BigDecimal totalOpenTime = BigDecimal.ZERO;
            List<Long> serverIdList = ghostConfig.getActivityInfo().getServerIdList();
            List<ServerInfo> infoList = ServerBussiness.getServerInfoListByServerIdList(serverIdList);
            long activityTime = ghostConfig.getActivityInfo().getBeginShowTime() * 1000 + ghostConfig.getStartOperationTime();
            for (ServerInfo serverInfo : infoList) {
                long subTime = activityTime - serverInfo.getOpenTime() * 1000;
                totalOpenTime = totalOpenTime.add(new BigDecimal(subTime <= 0 ? 0 : subTime));
            }
            avgOpenDay = totalOpenTime
                    .divide(BigDecimal.valueOf(infoList.size()), 0, BigDecimal.ROUND_UP)
                    .divide(new BigDecimal(DateHelper.DAY_MILLIONS), 0, BigDecimal.ROUND_DOWN)
                    .intValue();

            ghostData.setAvgOpenDay(avgOpenDay);
        }

        BigDecimal enlargedAbility = BigDecimal.valueOf(avgAbility)
                .multiply(BigDecimal.valueOf(1000 + ghostConfig.getAbilityEnlargeValue(avgOpenDay)))
                .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP);
        logger.info("【鬼市计算数值】活动ID={}，放大{}，新赚钱值={}", ghostConfig.getActivityId(), (1000 + ghostConfig.getAbilityEnlargeValue(avgOpenDay)), enlargedAbility.toBigInteger().toString());
        logger.info("ghost openDays: {}, enlarge: {}, param: {}", avgOpenDay,ghostConfig.getAbilityEnlargeValue(avgOpenDay),ghostConfig.getAbilityEnlargeMap());

        // 获取血量放大系数
        int hpLarge = 1000;
        for (int i = 0; i < ghostConfig.getHpDayList().size(); i++) {
            hpLarge = ghostConfig.getHpValueList().get(i);
            if (avgOpenDay < ghostConfig.getHpDayList().get(i)) {
                break;
            }
        }
        logger.info("【鬼市计算数值】活动ID={}，开服{}天，血量放大系数{}", ghostConfig.getActivityId(), avgOpenDay, hpLarge);

        // 生成各类型boss
        Map<Integer, Map<Integer, GhostBossData>> bossDataMap = new ConcurrentHashMap<>();
        List<GhostBossConfig> bossConfigList = ghostConfig.getBossConfigList();
        for (GhostBossConfig bossConfig : bossConfigList) {

            bossDataMap.put(bossConfig.getBossType(), new ConcurrentHashMap<>());

            long bossHp = 0L; // 单只血量
            int bossCount = 0; // 数量
            if (bossConfig.isBigBoss()) {
                //v6.5.0,大BOSS血量优化
                bossHp = this.createBigBossHp(batchNo);
                if (bossHp <= 0) {
                    //走原来的逻辑
                    bossHp = enlargedAbility.multiply(BigDecimal.valueOf(bossConfig.getHpPer())).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).longValue();
                    long minHp = BigDecimal.valueOf(bossConfig.getHp()).multiply(BigDecimal.valueOf(hpLarge)).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).longValue();
                    // 活阎王保底血量
                    if (bossHp < minHp) {
                        bossHp = minHp;
                    }
                }
                bossCount = 1;
                logger.info("【鬼市计算数值】活动ID={}，活阎王血量{}", ghostConfig.getActivityId(), bossHp);
            } else {
                bossHp = BigDecimal.valueOf(bossConfig.getHp()).multiply(BigDecimal.valueOf(hpLarge)).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).longValue();
                bossCount = enlargedAbility
                        .multiply(new BigDecimal(bossConfig.getHpPer()))
                        .divide(new BigDecimal(1000), 0, BigDecimal.ROUND_UP)
                        .divide(new BigDecimal(bossHp), 0, BigDecimal.ROUND_UP).intValue();
                logger.info("【鬼市计算数值】活动ID={}，类型{}，boss基础血量{}，放大后单只血量{}。该类型总血量{}，数量{}",
                        ghostConfig.getActivityId(),
                        bossConfig.getBossType(),
                        bossConfig.getHp(),
                        bossHp,
                        enlargedAbility
                                .multiply(new BigDecimal(bossConfig.getHpPer()))
                                .divide(new BigDecimal(1000), 0, BigDecimal.ROUND_UP),
                        bossCount);
            }

            for (int i = 0; i < bossCount; i++) {
                GhostBossData bossData = createBoss(batchNo, bossConfig.getBossType(), bossHp);
                bossDataMap.get(bossConfig.getBossType()).put(bossData.getBossId(), bossData);
            }

        }

        checkBossMap(bossDataMap);
        return bossDataMap;
    }

    /**
     * 计算大boss血量
     * @param batchNo
     * @return
     */
    private long createBigBossHp(int batchNo) {
        if (ghostConfig.getActivityInfo().getServerIdList().size() > this.userAbilityMap.size()) {
            logger.error("鬼市收集玩家战力信息异常，activityId:{}，serverList:{}", ghostConfig.getActivityInfo().getActivityId(), this.userAbilityMap.keySet());
            return 0;
        }
        // v6.5.0 Boss血量计算改为 依照玩家排名门客战力总值获取指定参数
        List<Long> userAbilityList = new ArrayList<>();
        long finalHp = 0L;
        for (Map<Long, GhostUserAbility> map : this.userAbilityMap.values()) {
            for (GhostUserAbility ghostUserAbility : map.values()) {
                userAbilityList.add(ghostUserAbility.getUserAbility());
            }
        }
        //排序一下
        userAbilityList.sort(new Comparator<Long>() {
            @Override
            public int compare(Long o1, Long o2) {
                return o2.compareTo(o1);
            }
        });
        //根据战力排名计算BOSS血量
        int userNumber = userAbilityList.size();
        List<Integer> userFloorEnlarge = ghostConfig.getBossHpParam1();
        List<Integer> bossHpEnlarge = ghostConfig.getBossHpParam2().get(batchNo - 1);
        int startIndex = 0;
        for(int i = 0;i < userFloorEnlarge.size();i++){
            // 找出此处的定位
            int endIndex = userFloorEnlarge.get(i) * userNumber / 1000;
            long sum = 0;
            for(long num : userAbilityList.subList(startIndex, endIndex)){
                sum += num;
            }
            finalHp += sum * bossHpEnlarge.get(i) / 1000;
            startIndex = endIndex;
        }
        return finalHp;
    }

    /**
     * 生成送财奖励
     */
    private List<GhostDisperseData> createBatchDisperse(int batchNo, int type) {
        List<GhostDisperseData> list = new ArrayList<>();
        List<GhostDisperseConfig> disperseConfigList = type == 1 ? ghostConfig.getDisperseConfigList() : ghostConfig.getDisperseConfigList2();
        for (GhostDisperseConfig config : disperseConfigList) {
            GhostDisperseData data = new GhostDisperseData();
            data.setActivityId(ghostConfig.getActivityId());
            data.setBatchNo(batchNo);
            data.setType(type);
            data.setDisperseId(ghostData.getNextDisperseId());
            data.setCount(config.getCount());
            data.setReward(config.getReward());
            data.setNotice(config.isNotice());
            data.setWeight(config.getWeight());
            data.setInsertOption();
            list.add(data);
        }
        return list;
    }

    /**
     * 检查每日数据重置
     */
    public void checkDailyResetData() {
        // 区服能力值是否上传完毕
        if (ghostData.getAvgAbility() <= 0) {
            if (ghostData.getAbilityMap().size() < ghostConfig.getActivityInfo().getServerIdList().size()) {
                return;
            }
            // 检验一下是不是全部为0，全部为0就不生成
            boolean isAbilityEnough = false;
            for (List<Long> list : ghostData.getAbilityMap().values()) {
                for (long ability : list) {
                    if (ability > 0) {
                        isAbilityEnough = true;
                        break;
                    }
                }
                if (isAbilityEnough) {
                    break;
                }
            }
            if (!isAbilityEnough) {
                return;
            }
        }

        // 检查重置时间
        long now = System.currentTimeMillis();

        // 重置
        synchronized (lockObject) {

            if (ghostConfig.getActivityInfo().getEndTime() < now / 1000) {
                // 活动已结束，不用再生成了
                return;
            }

            long lastResetTime = calLastResetTime();
            // 判断重置时间
            if (lastResetTime <= ghostData.getLastResetTime()) {
                return;
            }

            int nextBatchNo = ghostData.getMaxBatchNo() + 1;

            // boss数据
            Map<Integer, Map<Integer, Map<Integer, GhostBossData>>> bossMap = ghostData.getBossMap();
            if (!bossMap.containsKey(nextBatchNo)) {
                Map<Integer, Map<Integer, GhostBossData>> tempBossMap = createBatchBoss(nextBatchNo);
                bossMap.put(nextBatchNo, tempBossMap);

                int count = 0;
                for (Map<Integer, GhostBossData> value : tempBossMap.values()) {
                    count += value.size();
                }
                ghostData.setBossCount(new AtomicInteger(count));
            }

            // 送财
            Map<Integer, Map<Integer, List<GhostDisperseData>>> disperseMap = ghostData.getDisperseMap();
            if (!disperseMap.containsKey(nextBatchNo)) {
                List<GhostDisperseData> list1 = createBatchDisperse(nextBatchNo, 1);
                List<GhostDisperseData> list2 = createBatchDisperse(nextBatchNo, 2);
                disperseMap.put(nextBatchNo, new ConcurrentHashMap<>());
                disperseMap.get(nextBatchNo).put(1, list1);
                disperseMap.get(nextBatchNo).put(2, list2);
            }

            // 商会情报
            Map<Integer, Map<String, Map<Integer, List<GhostUnionNews>>>> unionNewsMap = ghostData.getUnionNewsMap();
            if (!unionNewsMap.containsKey(nextBatchNo)) {
                unionNewsMap.put(nextBatchNo, new ConcurrentHashMap<>());
            }

            ghostData.setMaxBatchNo(nextBatchNo);
            ghostData.setLastResetTime(lastResetTime);

            // 重新计算今日boss数量、今日宝箱数量
            initTodayCount();

            // 重置援军值
            ghostData.setCostAbility(0L);

            // 同步活动刷新
            for (Long serverId : ghostConfig.getActivityInfo().getServerIdList()) {
                GhostActivityProto.SyncGhostActivityRefreshRespMsg.Builder builder = GhostActivityProto.SyncGhostActivityRefreshRespMsg.newBuilder();
                MessageHelper.sendPacket(serverId, 0, YanQuMessageUtils.buildMessage(GameProtocol.S_GHOST_SYNC_REFRESH_FROM_CROSS, builder));
            }
        }
    }

    /**
     * 初始化今日鬼市数据
     */
    public void initTodayCount() {

        if (ghostData.getMaxBatchNo() <= 0) {
            return;
        }

        int count = 0;
        for (Map<Integer, GhostBossData> bossDataMap : ghostData.getBossMap().get(ghostData.getMaxBatchNo()).values()) {
            for (GhostBossData bossData : bossDataMap.values()) {
                if (bossData.getCurHp() > 0) {
                    count++;
                }
            }
        }
        ghostData.setBossCount(new AtomicInteger(count));

    }

    /**
     * 根据Id获取boss
     *
     * @param type boss类型，不知道就传-1
     */
    public GhostBossData getGhostBossData(int type, int bossId) {
        Map<Integer, Map<Integer, GhostBossData>> bossMap = ghostData.getBossMap().get(ghostData.getMaxBatchNo());
        if (type != -1) {
            if (bossMap.containsKey(type)) {
                return bossMap.get(type).get(bossId);
            } else {
                return null;
            }
        } else {
            for (Map<Integer, GhostBossData> map : bossMap.values()) {
                if (map.containsKey(bossId)) {
                    return map.get(bossId);
                }
            }
            return null;
        }
    }

    /**
     * 探索
     */
    public int explore(long userId, PlayerProto.PlayerBaseTempMsg playerBaseTempMsg, long userResetTime, int exploreTimes) {

        int eventType = 0;
        String eventParam = "";

        Random random = new Random();
        List<Integer> weightList = new ArrayList<>(ghostConfig.getEventWeightList());
        synchronized (lockObject) {

            // 请求校验
            int ret = checkGhostRequest(userResetTime, true);
            if (ret != 0) {
                return ret;
            }

            eventType = RandomHelper.getRandomIndexByWeight(weightList, random) + 1;
            switch (eventType) {
                case 1:
                    // id|类型|是否发现最终boss
                    eventParam = exploreBoss(random, userId, playerBaseTempMsg, exploreTimes);
                    break;
                case 2:
                    // 箱子id（没数量后都是0）|宝箱道具id
                    eventParam = newExploreBox(random);
                    break;
                case 3:
                    // 真奖励|假奖励
                    eventParam = exploreGuess(random);
                    break;
            }
        }

        if (eventType == 0 || StringUtils.isNullOrEmpty(eventParam)) {
            logger.error("GhostActivity error on explore! eventType={}, eventParam={}, bossCount={}, userId={}.",
                    eventType, eventParam, ghostData.getBossCount().intValue(), userId);
            return GameErrorCode.E_GHOST_ACTIVITY_NO_OPEN;
        }

        GhostActivityProto.CrossExploreRespMsg.Builder builder = GhostActivityProto.CrossExploreRespMsg.newBuilder();
        builder.setRet(0);
        builder.setEventType(eventType);
        builder.setParam(eventParam);
        builder.setTodayGhostData(GhostPb.parseTodayGhostDataMsg(ghostData, ghostConfig));
        builder.setUserResetTime(userResetTime);
        MessageHelper.sendPacket(playerBaseTempMsg.getServerId(), userId, YanQuMessageUtils.buildMessage(GameProtocol.S_GHOST_EXPLORE_FROM_CROSS, builder));
        return 0;
    }

    /**
     * 探索boss事件
     */
    private String exploreBoss(Random random, long userId, PlayerProto.PlayerBaseTempMsg playerBaseTempMsg, int exploreTimes) {
        List<GhostBossConfig> bossConfigList = ghostConfig.getBossConfigList();
        List<Integer> aliveType = bossConfigList.stream().mapToInt(GhostBossConfig::getBossType).boxed().collect(Collectors.toList());
        List<Integer> weightList = bossConfigList.stream().mapToInt(GhostBossConfig::getWeight).boxed().collect(Collectors.toList());
        List<GhostBossData> aliveIdList = new ArrayList<>();

        // 获取活阎王权重加成
        int addWeight = exploreTimes / ghostConfig.getBigBossAddiTimes() * ghostConfig.getBigBossAddiWeight();
        // 找活阎王类型
        for (GhostBossConfig bossConfig : ghostConfig.getBossConfigList()) {
            if (bossConfig.isBigBoss()) {
                // 找List的改权重
                for (int i = 0; i < aliveType.size(); i++) {
                    if (aliveType.get(i) == bossConfig.getBossType()) {
                        weightList.set(i, weightList.get(i) + addWeight);
                        break;
                    }
                }
                break;
            }
        }

        GhostBossData randomBoss = null;

        for (int i = 0; i < bossConfigList.size(); i++) {
            // 随机一个类型
            int typeIndex = RandomHelper.getRandomIndexByWeight(weightList, random);
            int bossType = aliveType.get(typeIndex);
            // 看看这个类型是否有存活boss
            Map<Integer, GhostBossData> bossDataMap = ghostData.getBossMap().get(ghostData.getMaxBatchNo()).get(bossType);
            for (GhostBossData bossData : bossDataMap.values()) {
                if (bossData.getCurHp() > 0) {
                    aliveIdList.add(bossData);
                }
            }

            if (aliveIdList.size() > 0) {
                randomBoss = aliveIdList.get(random.nextInt(aliveIdList.size()));
                break;
            } else {
                // 没有存活boss，则去掉该类型，其余的类型再随机
                aliveType.remove(typeIndex);
                weightList.remove(typeIndex);
            }
        }

        // 异常容错
        if (randomBoss == null) {
            return "";
        }

        // 判断是否第一个发现最终boss
        boolean firstFind = false;
        boolean bigBoss = false;
        for (GhostBossConfig bossConfig : bossConfigList) {
            if (bossConfig.getBossType() == randomBoss.getBossType()) {
                if (bossConfig.isBigBoss()) {
                    bigBoss = true;
                    GhostDispersePlayer findPlayer = getGhostDispersePlayer(1, ghostData.getMaxBatchNo());
                    if (findPlayer == null) {
                        addGhostDispersePlayer(1, ghostData.getMaxBatchNo(), PlayerBasePb.parseToUserBaseInfo(playerBaseTempMsg), userId);
                        firstFind = true;
                        // 同步送财消息
                        syncDisperse(1, userId, playerBaseTempMsg);
                    }
                }
                break;
            }
        }

        // 情报
        if (!StringUtils.isNullOrEmpty(playerBaseTempMsg.getUnionUid())) {
            boolean addSucc = addUnionNews(playerBaseTempMsg.getUnionUid(), randomBoss, 1, userId);
            if (addSucc) {
                syncUnionNewsRedHot(playerBaseTempMsg.getUnionUid(), playerBaseTempMsg.getServerId(),0);
            }
        }

        // 返回
        return randomBoss.getBossId() + "|" + randomBoss.getBossType() + "|" + (firstFind ? 1 : 0) + "|" + (bigBoss ? 1 : 0);
    }

    /**
     * 探索货箱事件（无数量、过期时间限制）
     */
    private String newExploreBox(Random random) {
        List<GhostBoxConfig> boxConfigList = ghostConfig.getBoxConfigList();
        List<Integer> weightList = new ArrayList<>();
        for (GhostBoxConfig config : boxConfigList) {
            weightList.add(config.getWeight());
        }
        int index = random.nextInt(weightList.size());
        GhostBoxConfig boxConfig = boxConfigList.get(index);
        return "0|" + boxConfig.getBoxItemId();
    }

    /**
     * 探索闷包事件
     */
    private String exploreGuess(Random random) {
        List<GhostGuessConfig> configList = ghostConfig.getGuessConfigList();
        GhostGuessConfig guessConfig = configList.get(random.nextInt(configList.size()));
        return guessConfig.getRealReward() + "|" + guessConfig.getFakeReward();
    }

    /**
     * 添加商会情报
     *
     * @param type 1发现新boss，2击杀boss
     */
    private boolean addUnionNews(String unionUid, GhostBossData bossData, int type, long userId) {

        // 【初始化Map】
        Map<String, Map<Integer, List<GhostUnionNews>>> batchNewsMap = ghostData.getUnionNewsMap().get(ghostData.getMaxBatchNo());
        if (!batchNewsMap.containsKey(unionUid)) {
            batchNewsMap.put(unionUid, new ConcurrentHashMap<>());
        }
        Map<Integer, List<GhostUnionNews>> newsMap = batchNewsMap.get(unionUid);
        if (!newsMap.containsKey(1)) {
            newsMap.put(1, new ArrayList<>());
        }
        if (!newsMap.containsKey(2)) {
            newsMap.put(2, new ArrayList<>());
        }

        // 0不添加，1添加，2替换
        int operateType = 0;
        List<GhostUnionNews> newsList = batchNewsMap.get(unionUid).get(type);

        // 【无效情报】
        if (type == 2) {
            operateType = 1;
        }
        // 【有效情报】
        else {
            boolean hadThisBoss = false;
            int curCount = 0;
            int maxCount = ghostConfig.getMaxAliveNewsCount();

            for (GhostUnionNews unionNews : newsList) {
                if (unionNews.getBossId() == bossData.getBossId()) {
                    hadThisBoss = true;
                    break;
                }
                GhostBossData tmpBoss = ghostData.getBossMap().get(ghostData.getMaxBatchNo()).get(unionNews.getBossType()).get(unionNews.getBossId());
                if (tmpBoss.getCurHp() > 0) {
                    curCount++;
                }
                if (curCount >= maxCount) {
                    break;
                }
            }

            if (hadThisBoss) {
                operateType = 0; // 有这个boss，无法添加
            } else if (curCount < maxCount) {
                operateType = 1; // 数量没超，可以添加
            } else {
                for (GhostBossConfig bossConfig : ghostConfig.getBossConfigList()) {
                    if (bossConfig.getBossType() == bossData.getBossType()) {
                        if (bossConfig.isBigBoss()) {
                            operateType = 2; // 没有这个boss && 数量超了 && 是活阎王，替换
                        } else {
                            operateType = 0;
                        }
                        break;
                    }
                }
            }
        }

        // 【处理结果】
        if (operateType == 0) {
            return false;
        } else if (operateType == 1) {
            GhostUnionNews unionNews = new GhostUnionNews();
            unionNews.setActivityId(ghostConfig.getActivityId());
            unionNews.setBatchNo(ghostData.getMaxBatchNo());
            unionNews.setUnionUid(unionUid);
            unionNews.setId(ghostData.getNextNewsId());
            unionNews.setType(type);
            unionNews.setBossType(bossData.getBossType());
            unionNews.setBossId(bossData.getBossId());
            unionNews.setUserId(userId);
            unionNews.setInsertOption();
            newsList.add(unionNews);
            return true;
        } else if (operateType == 2) {
            GhostUnionNews smallNews = null;
            long smallNewsHp = 0;
            for (GhostUnionNews unionNews : newsList) {
                GhostBossData tmpBoss = ghostData.getBossMap().get(ghostData.getMaxBatchNo()).get(unionNews.getBossType()).get(unionNews.getBossId());
                if (tmpBoss.getCurHp() > 0) {
                    if (smallNews == null || smallNews.getBossType() > unionNews.getBossType()) { // 类型最小
                        smallNews = unionNews;
                    } else if (smallNews.getBossType() == unionNews.getBossType() && smallNewsHp < tmpBoss.getCurHp()) { // 血量最高
                        smallNews = unionNews;
                    }
                }
            }
            if (smallNews != null) {
                smallNews.setBossType(bossData.getBossType());
                smallNews.setBossId(bossData.getBossId());
                smallNews.setUserId(userId);
                smallNews.setUpdateOption();
                return true;
            } else {
                return false;
            }
        }

        return false;
    }

    /**
     * 攻击boss
     */
    public int attackBoss(long serverId, int patronsId, String cost, int bossId, long ability, int buffAddition,
                          int talentAddition, int attackTimes, UserBaseInfo userBaseInfo, long userId,
                          String unionUid, long userResetTime) {
        synchronized (lockObject) {

            // 请求校验
            int ret = checkGhostRequest(userResetTime, true);
            if (ret != 0) {
                return ret;
            }

            GhostBossData bossData = null;
            long damage = 0;
            boolean isKill = false;
            String bigBossStageReward = "";

            // 获取Boss
            bossData = getGhostBossData(-1, bossId);
            if (bossData == null) {
                return GameErrorCode.E_GHOST_ACTIVITY_BOSS_DEAD;
            }

//            // 商会情报Map<批次，商会UID，类型，情报数据>    类型：1发现，2击杀
//            Map<Integer, Map<String, Map<Integer, List<GhostUnionNews>>>> unionNewsMap = ghostData.getUnionNewsMap();
//            if (!unionNewsMap.containsKey(bossData.getBatchNo())) {
//                return GameErrorCode.E_GHOST_ACTIVITY_CAN_NOT_FIND_BOSS;
//            }
//            if (!unionNewsMap.get(bossData.getBatchNo()).containsKey(unionUid)) {
//                return GameErrorCode.E_GHOST_ACTIVITY_CAN_NOT_FIND_BOSS;
//            }
//            if (!unionNewsMap.get(bossData.getBatchNo()).get(unionUid).containsKey(1)) {
//                return GameErrorCode.E_GHOST_ACTIVITY_CAN_NOT_FIND_BOSS;
//            }
//            boolean findBoss = false;
//            List<GhostUnionNews> unionNews = new ArrayList<>(unionNewsMap.get(bossData.getBatchNo()).get(unionUid).get(1));
//            for (GhostUnionNews unionNew : unionNews) {
//                if (unionNew.getBossId() == bossId) {
//                    findBoss = true;
//                    break;
//                }
//            }
//            if (!findBoss) {
//                return GameErrorCode.E_GHOST_ACTIVITY_CAN_NOT_FIND_BOSS;
//            }


            // 攻击
            if (bossData.getCurHp() <= 0) {
                GhostActivityProto.CrossAttackBossRespMsg.Builder builder = GhostActivityProto.CrossAttackBossRespMsg.newBuilder();
                builder.setRet(GameErrorCode.E_GHOST_ACTIVITY_BOSS_DEAD);
                builder.setPatronsId(patronsId);
                builder.setCost(cost);
                builder.setAttackTimes(attackTimes);
                builder.setBossData(GhostPb.parseGhostBossDataMsg(bossData));
                MessageHelper.sendPacket(serverId, userId, YanQuMessageUtils.buildMessage(GameProtocol.S_GHOST_ATTACK_BOSS_FROM_CROSS, builder));
                return GameErrorCode.E_GHOST_ACTIVITY_BOSS_DEAD;
            }

            // 天赋加成处理（对最终boss无效）
            if (talentAddition > 0) {
                for (GhostBossConfig bossConfig : ghostConfig.getBossConfigList()) {
                    if (bossConfig.getBossType() == bossData.getBossType()) {
                        talentAddition = bossConfig.isBigBoss() ? 0 : talentAddition;
                        break;
                    }
                }
            }

            // 计算伤害
            long theoryDamage = BigDecimal.valueOf(ability)
                    .multiply(BigDecimal.valueOf(1000).add(BigDecimal.valueOf(buffAddition)))
                    .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP)
                    .multiply(BigDecimal.valueOf(1000).add(BigDecimal.valueOf(talentAddition)))
                    .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).longValue();
            damage = bossData.getCurHp() < theoryDamage ? bossData.getCurHp() : theoryDamage;

            // 扣血
            bossData.setCurHp(bossData.getCurHp() - damage);
            isKill = bossData.getCurHp() <= 0;
            if (isKill) {
                bossData.setKiller(userBaseInfo);
                bossData.setKillTime(System.currentTimeMillis());
                bossData.setUserId(userId);
                if (!StringUtils.isNullOrEmpty(unionUid)) {
                    addUnionNews(unionUid, bossData, 2, userId);
                }

                ghostData.getBossCount().decrementAndGet();
            }

            // 计算阶段奖励
            bigBossStageReward = getBigBossStageReward(bossData, damage);

            // 加攻击记录 加伤害榜单
            addAttackRecord(bossData.getBatchNo(), bossId, serverId, userId, userBaseInfo, damage);

            // 同步其他玩家
            addGhostPlayerAction(3, bossId, GhostPb.parseGhostSimplePlayer(userId, serverId, userBaseInfo.getNickName(), userBaseInfo.getDecoration()), damage);

            // 返回
            GhostActivityProto.CrossAttackBossRespMsg.Builder builder = GhostActivityProto.CrossAttackBossRespMsg.newBuilder();
            builder.setRet(0);
            builder.setPatronsId(patronsId);
            builder.setCost(cost);
            builder.setAttackTimes(attackTimes);
            builder.setRealDamage(damage);
            builder.setBossData(GhostPb.parseGhostBossDataMsg(bossData));
            builder.setIsKill(isKill);
            builder.setStageReward(bigBossStageReward);
            builder.setUserResetTime(userResetTime);
            MessageHelper.sendPacket(serverId, userId, YanQuMessageUtils.buildMessage(GameProtocol.S_GHOST_ATTACK_BOSS_FROM_CROSS, builder));

            // 援兵判断
            if (!StringUtils.isNullOrEmpty(cost)) {
                addYuanBingAbility(theoryDamage);
            }
            // 触发援兵判断
            triggerYuanBing();

        }
        // 返回之后再判断同步
        if (needAdvanceSyncAction()) {
            syncGhostPlayerAction(true);
        }
        return 0;
    }

    /**
     * 领取鬼市送财奖励
     */
    public int getDisperseReward(int type, long serverId, long userId, long userResetTime) {

        boolean isSpec = false; // type1 && 发现最终boss || type2 && 击杀最后一只boss
        String reward = "";
        boolean isNotice = false;

        synchronized (lockObject) {

            // 请求校验
            int ret = checkGhostRequest(userResetTime, false);
            if (ret != 0) {
                return ret;
            }

            GhostDispersePlayer player = getGhostDispersePlayer(type, ghostData.getMaxBatchNo());

            if (player == null) {
                return GameErrorCode.E_GHOST_ACTIVITY_NO_FIND_BIG_BOSS;
            }

            if (player.getUserBaseInfo().getServerId() == serverId && player.getUserId() == userId) {
                isSpec = true;
            }

            if (isSpec) {
                reward = type == 1 ? ghostConfig.getBigBossFindReward() : ghostConfig.getFinalKillReward();
                isNotice = true;
            } else {
                GhostDisperseData disperseData = drawDisperseReward(type);
                if (disperseData != null) { // 没有随机奖励就只有元宝了
                    reward = disperseData.getReward();
                    isNotice = disperseData.isNotice();
                }
            }

        }

        GhostActivityProto.CrossGetDisperseGoldRewardRespMsg.Builder builder = GhostActivityProto.CrossGetDisperseGoldRewardRespMsg.newBuilder();
        builder.setRet(0);
        builder.setRandomReward(reward);
        builder.setIsNotice(isNotice);
        builder.setIsSpec(isSpec);
        builder.setType(type);
        builder.setUserResetTime(userResetTime);
        MessageHelper.sendPacket(serverId, userId, YanQuMessageUtils.buildMessage(GameProtocol.S_GHOST_GET_DISPERSE_REWARD_FROM_CROSS, builder));
        return 0;
    }

    /**
     * 抽一份送财奖励
     *
     * @return 引用值，别改数量
     */
    public GhostDisperseData drawDisperseReward(int type) {
        boolean hasReward = false;
        List<Integer> weight = new ArrayList<>();
        List<GhostDisperseData> dataList = ghostData.getDisperseMap().get(ghostData.getMaxBatchNo()).get(type);
        for (GhostDisperseData disperseData : dataList) {
            if (disperseData.getCount() > 0 || disperseData.getCount() == -1) {  // -1表示无限数量
                weight.add(disperseData.getWeight());
                hasReward = true;
            } else {
                weight.add(0);
            }
        }
        if (!hasReward) {
            return null;
        }
        int index = RandomHelper.getRandomIndexByWeight(weight, new Random());
        if (index >= dataList.size()) {
            return null;
        }

        GhostDisperseData disperseData = dataList.get(index);
        disperseData.setCount(disperseData.getCount() == -1 ? -1 : disperseData.getCount() - 1);
        return disperseData;
    }

    /**
     * 获取商会情报的Boss
     *
     * @param type 1有效，2无效
     */
    public List<GhostActivityProto.GhostUnionNewsMsg> getUnionNewsMsgList(String unionUid, int type) {
        Map<String, Map<Integer, List<GhostUnionNews>>> newsMap = ghostData.getUnionNewsMap().get(ghostData.getMaxBatchNo());
        if (!newsMap.containsKey(unionUid)) {
            return new ArrayList<>();
        } else {
            List<GhostActivityProto.GhostUnionNewsMsg> resultList = new ArrayList<>();
            int maxCount = type == 1 ? ghostConfig.getMaxAliveNewsCount() : ghostConfig.getMaxDeadNewsCount();
            List<GhostUnionNews> unionNewsList = newsMap.get(unionUid).get(type);
            int size = unionNewsList.size();
            for (int i = size - 1; i >= 0; i--) {
                GhostUnionNews unionNews = unionNewsList.get(i);
                GhostBossData bossData = getGhostBossData(unionNews.getBossType(), unionNews.getBossId());
                if (bossData == null) continue;
                if (type == 1 && bossData.getCurHp() > 0
                        || type == 2) {
                    resultList.add(GhostPb.parseGhostUnionNewsMsg(unionNews, bossData).build());
                }
                if (resultList.size() >= maxCount) {
                    break;
                }
            }
            return resultList;
        }
    }

    /**
     * 添加攻击记录
     */
    public void addAttackRecord(int batchNo, int bossId, long serverId, long userId, UserBaseInfo userBaseInfo, long damage) {
        // 获取boss伤害记录
        Map<Integer, Map<Integer, Map<Long, GhostAttackRecord>>> attackRecordMap = ghostData.getAttackRecordMap();
        if (!attackRecordMap.containsKey(batchNo) || !attackRecordMap.get(batchNo).containsKey(bossId)) {
            if (!attackRecordMap.containsKey(batchNo)) {
                attackRecordMap.put(batchNo, new ConcurrentHashMap<>());
            }
            if (!attackRecordMap.get(batchNo).containsKey(bossId)) {
                attackRecordMap.get(batchNo).put(bossId, new ConcurrentHashMap<>());
            }
        }
        Map<Long, GhostAttackRecord> recordMap = attackRecordMap.get(batchNo).get(bossId);
        // 获取用户伤害记录
        if (!recordMap.containsKey(userId)) {
            GhostAttackRecord attackRecord = new GhostAttackRecord();
            attackRecord.setActivityId(ghostConfig.getActivityId());
            attackRecord.setBatchNo(batchNo);
            attackRecord.setBossId(bossId);
            attackRecord.setServerId(serverId);
            attackRecord.setUserId(userId);
            attackRecord.setUserBaseInfo(userBaseInfo);
            attackRecord.setDamage(0);
            attackRecord.setUpdateTime(System.currentTimeMillis());
            attackRecord.setInsertOption();
            recordMap.put(userId, attackRecord);
        }
        GhostAttackRecord attackRecord = recordMap.get(userId);
        // 加伤害
        attackRecord.setDamage(attackRecord.getDamage() + damage);
        attackRecord.setUserBaseInfo(userBaseInfo);
        attackRecord.setUpdateTime(System.currentTimeMillis());

        // 榜单变化
        CrossActivityRankListModel rankListModel = getRankListModel(bossId);
        rankListModel.rankChange(createCrossUserRank(attackRecord));
    }

    /**
     * 清理攻击记录旧数据
     */
    public void cleanOldAttackRecordMap() {
        List<Integer> bossIdList = new ArrayList<>();

        for (Map.Entry<Integer, CrossActivityRankListModel> entry : damageRankListMap.entrySet()) {
            int bossId = entry.getKey();
            if (isOldBoss(bossId)) {
                bossIdList.add(bossId);
            }
        }

        Map<Integer, Map<Long, GhostAttackRecord>> mapMap = ghostData.getAttackRecordMap().get(ghostData.getMaxBatchNo());
        for (Integer bossId : bossIdList) {
            // 清空攻击记录（这里只清空最新批次的boss，旧批次的save完了会全部清空）
            if (mapMap != null) {
                mapMap.remove(bossId);
            }
            // 同时清空榜单
            damageRankListMap.remove(bossId);
        }
    }

    /**
     * 是否是旧boss
     */
    private boolean isOldBoss(int bossId) {
        GhostBossData bossData = getGhostBossData(-1, bossId);
        if (bossData == null) {
            return true;
        }
        if (bossData.getCurHp() <= 0
                && bossData.getKillTime() > 0
                && bossData.getKillTime() < System.currentTimeMillis() - 60 * 60 * 1000L) {
            return true;
        }
        return false;
    }

    /**
     * 获取boss伤害榜单
     */
    public CrossActivityRankListModel getRankListModel(int bossId) {
        synchronized (lockObject) {
            if (!damageRankListMap.containsKey(bossId)) {
                CrossActivityRankListModel rankListModel = new CrossActivityRankListModel(ghostConfig.getActivityId(), false);
                rankListModel.setRankNum(100);
                // 旧数据直接返回空，不加map
                if (isOldBoss(bossId)) {
                    return rankListModel;
                }
                damageRankListMap.put(bossId, rankListModel);
            }
        }
        return damageRankListMap.get(bossId);
    }

    /**
     * 生成用户排行
     */
    private CrossUserRank createCrossUserRank(GhostAttackRecord record) {
        CrossUserRank rank = new CrossUserRank();
        rank.setUserBaseInfo(record.getUserBaseInfo());
        rank.setUserId(record.getUserId());
        rank.setLastUpdateTime(record.getUpdateTime());
        rank.setValue(BigInteger.valueOf(record.getDamage()));
        return rank;
    }

    /**
     * 初始化怪物伤害榜单
     */
    private void initRankListModel() {
        damageRankListMap = new ConcurrentHashMap<>();
        Map<Integer, Map<Long, GhostAttackRecord>> recordMap = ghostData.getAttackRecordMap().get(ghostData.getMaxBatchNo());
        for (Map.Entry<Integer, Map<Long, GhostAttackRecord>> mapEntry : recordMap.entrySet()) {
            Integer bossId = mapEntry.getKey();
            CrossActivityRankListModel rankListModel = getRankListModel(bossId);
            LinkedList<CrossUserRank> rankList = new LinkedList<>();
            for (GhostAttackRecord attackRecord : mapEntry.getValue().values()) {
                rankList.add(createCrossUserRank(attackRecord));
            }
            rankListModel.setRankList(rankList);
        }
    }

    /**
     * 进入房间
     *
     * @return 返回房间内玩家
     */
    public List<GhostSimplePlayer> enterRoom(int bossId, GhostSimplePlayer simplePlayer) {
        sceneLogic.enterRoom(simplePlayer, bossId);
        addGhostPlayerAction(1, bossId, simplePlayer, 0);
        return sceneLogic.getRoomUserList(bossId, simplePlayer.getServerId(), simplePlayer.getUserId(), 30);
    }

    /**
     * 退出房间
     */
    public void quitRoom(GhostSimplePlayer simplePlayer) {
        int bossId = sceneLogic.quitRoom(simplePlayer);
        addGhostPlayerAction(2, bossId, simplePlayer, 0);

        if (needAdvanceSyncAction()) {
            syncGhostPlayerAction(true);
        }
    }

    /**
     * 添加玩家动作
     *
     * @param type 1进入房间，2退出房间，3攻击boss
     */
    private void addGhostPlayerAction(int type, int bossId, GhostSimplePlayer simplePlayer, long damage) {
        if (bossId == 0) {
            return;
        }
        GhostBossData bossData = getGhostBossData(-1, bossId);
        if (bossData == null) {
            return;
        }

        GhostActivityProto.GhostPlayerActionMsg.Builder builder = GhostActivityProto.GhostPlayerActionMsg.newBuilder();
        builder.setType(type);
        builder.setBossId(bossId);
        builder.setPlayerData(GhostPb.parseGhostSimplePlayerMsg(simplePlayer));
        builder.setBossHp(bossData.getCurHp());
        builder.setDamage(damage);
        synchronized (lockActionObject) {
            actionMsgList.add(builder.build());
        }
    }

    /**
     * 同步玩家动作
     */
    public void syncGhostPlayerAction(boolean checkSize) {
        LinkedList<GhostActivityProto.GhostPlayerActionMsg> tmpActionMsgList;

        synchronized (lockActionObject) {

            if (checkSize) {
                if (!needAdvanceSyncAction()) {
                    return;
                }
            }

            tmpActionMsgList = new LinkedList<>(actionMsgList);
            actionMsgList.clear();
        }

        if (tmpActionMsgList.size() > 0) {
            GhostActivityProto.SyncGhostPlayerActionRespMsg.Builder builder = GhostActivityProto.SyncGhostPlayerActionRespMsg.newBuilder();
            builder.addAllActionList(tmpActionMsgList);
            // 同步到各个区服
            YanQuMessage yanQuMessage = YanQuMessageUtils.buildMessage(GameProtocol.S_GHOST_SYNC_PLAYER_ACTION_FROM_CROSS, builder);
            for (Long serverId : ghostConfig.getActivityInfo().getServerIdList()) {
                MessageHelper.sendPacket(serverId, 0, yanQuMessage);
            }
        }

    }

    /**
     * 是否要提前同步玩家动作
     */
    public boolean needAdvanceSyncAction() {
        return actionMsgList.size() > 30;
    }

    /**
     * 同步送财到区服
     *
     * @param type 1发现最终boss，2boss全清
     */
    public void syncDisperse(int type, long userId, PlayerProto.PlayerBaseTempMsg playerBaseTempMsg) {
        GhostActivityProto.SyncGhostDisperseRespMsg.Builder builder = GhostActivityProto.SyncGhostDisperseRespMsg.newBuilder();
        builder.setType(type);
        builder.setUserId(userId);
        builder.setPlayer(playerBaseTempMsg);
        // 同步到各个区服
        for (Long tmpServerId : ghostConfig.getActivityInfo().getServerIdList()) {
            MessageHelper.sendPacket(tmpServerId, 0, YanQuMessageUtils.buildMessage(GameProtocol.S_GHOST_SYNC_DISPERSE_FROM_CROSS, builder));
        }
    }

    /**
     * 今日鬼市是否闭市
     */
    public boolean isTodayEnd() {
        return ghostData.getBossCount().intValue() <= 0;
    }

    /**
     * 活动数据是否重置完毕
     */
    public boolean isGhostDataResetFinish() {
        if (ghostData == null) {
            return false;
        }

        long lastResetTime = calLastResetTime();
        return ghostData.getLastResetTime() >= lastResetTime;
    }

    /**
     * 鬼市请求校验
     *
     * @param checkBatchEnd 是否需要检查本批结束
     */
    public int checkGhostRequest(long userResetTime, boolean checkBatchEnd) {
        if (ghostData == null) {
            return GameErrorCode.E_GHOST_ACTIVITY_NO_OPEN;
        }

        if (ghostData.getLastResetTime() == 0) {
            return GameErrorCode.E_GHOST_ACTIVITY_NO_OPEN;
        }

        if (checkBatchEnd && ghostData.getBossCount().intValue() <= 0) {
            return GameErrorCode.E_GHOST_ACTIVITY_BATCH_END;
        }

        if (userResetTime != ghostData.getLastResetTime()) {
            return GameErrorCode.E_GHOST_ACTIVITY_REFRESH;
        }

        return 0;
    }

    /**
     * 创建一只boss
     */
    private GhostBossData createBoss(int batchNo, int type, long bossHp) {
        GhostBossData bossData = new GhostBossData();
        bossData.setActivityId(ghostConfig.getActivityId());
        bossData.setBatchNo(batchNo);
        bossData.setBossId(ghostData.getNextBossId());
        bossData.setBossType(type);
        bossData.setTotalHp(bossHp);
        bossData.setCurHp(bossHp);
        bossData.setUserId(0);
        bossData.setKiller(new UserBaseInfo());
        bossData.setCreateTime(System.currentTimeMillis());
        bossData.setInsertOption();
        return bossData;
    }

    /**
     * 获取送财者信息
     */
    public GhostDispersePlayer getGhostDispersePlayer(int type, int batchNo) {
        Map<Integer, Map<Integer, GhostDispersePlayer>> dispersePlayerMap = ghostData.getDispersePlayerMap();
        if (!dispersePlayerMap.containsKey(batchNo)) {
            return null;
        }
        return dispersePlayerMap.get(batchNo).get(type);
    }

    /**
     * 获取送财者信息
     */
    public void addGhostDispersePlayer(int type, int batchNo, UserBaseInfo userBaseInfo, long userId) {
        Map<Integer, Map<Integer, GhostDispersePlayer>> dispersePlayerMap = ghostData.getDispersePlayerMap();
        if (!dispersePlayerMap.containsKey(batchNo)) {
            dispersePlayerMap.put(batchNo, new ConcurrentHashMap<>());
        }
        GhostDispersePlayer dispersePlayer = new GhostDispersePlayer();
        dispersePlayer.setActivityId(ghostConfig.getActivityId());
        dispersePlayer.setBatchNo(batchNo);
        dispersePlayer.setType(type);
        dispersePlayer.setUserId(userId);
        dispersePlayer.setUserBaseInfo(userBaseInfo);
        dispersePlayer.setTime(System.currentTimeMillis());
        dispersePlayer.setInsertOption();
        dispersePlayerMap.get(batchNo).put(type, dispersePlayer);
    }

    /**
     * 计算阶段奖励
     */
    public String getBigBossStageReward(GhostBossData bossData, long damage) {
        int stageChangeNum = 0;
        BigDecimal stageHp = BigDecimal.valueOf(bossData.getTotalHp()).divide(BigDecimal.valueOf(ghostConfig.getBigBossStageCount()), 4, BigDecimal.ROUND_DOWN);

        for (GhostBossConfig bossConfig : ghostConfig.getBossConfigList()) {
            if (bossConfig.getBossType() == bossData.getBossType()) {
                if (bossConfig.isBigBoss()) {
                    // 计算阶段数变化
                    long lastStageHp = 0;
                    int oldStage = 0;
                    int newStage = 0;
                    for (int i = 1; i <= ghostConfig.getBigBossStageCount(); i++) {
                        long curStageMax = stageHp.multiply(BigDecimal.valueOf(i)).setScale(0, BigDecimal.ROUND_UP).longValue();
                        if (bossData.getCurHp() > lastStageHp && bossData.getCurHp() <= curStageMax) {
                            oldStage = i;
                        }
                        if (bossData.getCurHp() + damage > lastStageHp && bossData.getCurHp() + damage <= curStageMax) {
                            newStage = i;
                        }
                        lastStageHp = curStageMax;
                    }
                    stageChangeNum = newStage - oldStage;
                }
            }
        }

        Property property = new Property();
        Random random = new Random();

        // 加阶段随机奖励
        for (int i = 0; i < stageChangeNum; i++) {
            int index = RandomHelper.getRandomIndexByWeight(ghostConfig.getBigBossStageWeightLis(), random);
            property.addProperty(PropertyHelper.parseStringToProperty(ghostConfig.getBigBossStageRewardList().get(index)));
        }

        // 加固定奖励，积分
        BigInteger count = BigDecimal.valueOf(bossData.getTotalHp())
                .multiply(BigDecimal.valueOf(ghostConfig.getDamageToScoreRatioList().get(0)))
                .multiply(BigDecimal.valueOf(ghostConfig.getBigBossStageScoreParam()))
                .multiply(BigDecimal.valueOf(getScoreDayAddition()))
                .divide(BigDecimal.valueOf(ghostConfig.getDamageToScoreRatioList().get(1)), 4, BigDecimal.ROUND_UP)
                .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP)
                .multiply(BigDecimal.valueOf(stageChangeNum)).setScale(0, BigDecimal.ROUND_UP).toBigInteger();
        property.addProperty(ghostConfig.getScoreId(), count);

        return PropertyHelper.parsePropertyToString(property);
    }

    /**
     * 检查bossMap
     */
    private void checkBossMap(Map<Integer, Map<Integer, GhostBossData>> batchBossMap) {
        for (GhostBossConfig bossConfig : ghostConfig.getBossConfigList()) {
            if (!batchBossMap.containsKey(bossConfig.getBossType())) {
                batchBossMap.put(bossConfig.getBossType(), new ConcurrentHashMap<>());
            }
        }
    }

    /**
     * 同步红点
     */
    private void syncUnionNewsRedHot(String unionUid, long serverId,long userId) {
        GhostActivityProto.CrossGhostSyncRedHotReqMsg.Builder builder = GhostActivityProto.CrossGhostSyncRedHotReqMsg.newBuilder();
        builder.setUnionUid(unionUid);
        if(userId != 0L){
            builder.addNoUserId(userId);
        }
        MessageHelper.sendPacket(serverId, 0, YanQuMessageUtils.buildMessage(GameProtocol.S_GHOST_SYNC_RED_HOT_FROM_CROSS, builder));
    }

    /**
     * 计算今日上次重置时间
     *
     * @return 今日第一个重置时间点没到，返回的是0
     */
    public long calLastResetTime() {
        long now = System.currentTimeMillis();
        long zeroTime = LocalDateTimeHelper.getZeroTimeTimeStamp();

        long lastResetTime = 0;
        for (Long tmpResetTime : ghostConfig.getRefreshTimeList()) {
            long nextResetTime = zeroTime + tmpResetTime;
            if (now < nextResetTime) {
                break;
            } else {
                lastResetTime = nextResetTime;
            }
        }
        return lastResetTime;
    }

    public Object getLockObject() {
        return lockObject;
    }

    /**
     * 添加援兵伤害量
     */
    private void addYuanBingAbility(long damage) {
        // 时间判断
        long now = System.currentTimeMillis();
        long endTime = ghostConfig.getYuanBingTriggerEndTime() + DateHelper.getTodayZeroTimeStamp();
        if (now > endTime) return;
        // 加援兵值
        ghostData.setCostAbility(ghostData.getCostAbility() + damage);
    }

    /**
     * 触发援兵
     */
    private void triggerYuanBing() {

        // 时间判断
        long now = System.currentTimeMillis();
        long endTime = ghostConfig.getYuanBingTriggerEndTime() + DateHelper.getTodayZeroTimeStamp();
        if (now > endTime) return;

        Map<Integer, Map<Integer, GhostBossData>> bossDataMap = getGhostData().getBossMap().get(ghostData.getMaxBatchNo());

        // boss数量判断
        if (ghostData.getBossCount().intValue() <= 0) return;

        // boss总血量初始化
        if (ghostData.getBatchBossTotalHp() == 0) {
            initBatchBossTotalHp();
        }

        // 判断活动BOSS总血量的30%
        long totalHp30 = BigDecimal.valueOf(ghostData.getBatchBossTotalHp())
                .multiply(BigDecimal.valueOf(ghostConfig.getYuanBingTriggerHpPercent()))
                .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).longValue();
        long curTotalHp = 0L;
        for (Map<Integer, GhostBossData> map : bossDataMap.values()) {
            for (GhostBossData bossData : map.values()) {
                if (bossData.getCurHp() > 0) curTotalHp += bossData.getCurHp();
            }
        }
        if (curTotalHp > totalHp30) return;

        // 获取各类型boss的血量
        Map<Integer, Long> bossHpMap = new ConcurrentHashMap<>();
        for (Map.Entry<Integer, Map<Integer, GhostBossData>> mapEntry : bossDataMap.entrySet()) {
            List<GhostBossData> bossList = new ArrayList<>(mapEntry.getValue().values());
            if (bossList.size() > 0) {
                bossHpMap.put(mapEntry.getKey(), bossList.get(0).getTotalHp());
            }
        }

        // 判断付费攻击量满足一批boss血量
        long needAbility = 0L;
        List<Integer> yuanBingBossTypeList = ghostConfig.getYuanBingBossTypeList();
        List<Integer> yuanBingBossCountList = ghostConfig.getYuanBingBossCountList();
        for (int i = 0; i < yuanBingBossTypeList.size(); i++) {
            int bossType = yuanBingBossTypeList.get(i);
            if (bossHpMap.containsKey(bossType)) {
                needAbility = needAbility + bossHpMap.get(bossType) * yuanBingBossCountList.get(i);
            }
        }
        if (ghostData.getCostAbility() < needAbility) return;

        // 生成援兵
        int addBossCount = 0;
        for (int i = 0; i < yuanBingBossTypeList.size(); i++) {
            int bossType = yuanBingBossTypeList.get(i);
            int bossCount = yuanBingBossCountList.get(i);
            if (bossHpMap.containsKey(bossType)) {
                long bossHp = bossHpMap.get(bossType);
                for (int j = 0; j < bossCount; j++) {
                    GhostBossData bossData = createBoss(ghostData.getMaxBatchNo(), bossType, bossHp);
                    bossDataMap.get(bossType).put(bossData.getBossId(), bossData);
                    ghostData.getBossCount().incrementAndGet();
                }
                addBossCount += bossCount;
            }
        }

        // 扣能力值
        ghostData.setCostAbility(ghostData.getCostAbility() - needAbility);

        // 同步援兵消息
        syncYuanBing(addBossCount);

        // 日志
        CrossAutoLogMgr.add(new LogGhostYuanBing(
                ghostConfig.getActivityId(),
                needAbility,
                ghostData.getCostAbility()
        ));
    }

    /**
     * 同步援兵消息
     */
    public void syncYuanBing(int bossCount) {
        for (long serverId : ghostConfig.getActivityInfo().getServerIdList()) {
            GhostActivityProto.SyncGhostYuanBingRespMsg.Builder builder = GhostActivityProto.SyncGhostYuanBingRespMsg.newBuilder();
            builder.setAddBossCount(bossCount);
            MessageHelper.sendPacket(serverId, 0, YanQuMessageUtils.buildMessage(GameProtocol.S_GHOST_SYNC_YUAN_BING_FROM_CROSS, builder));
        }
    }

    /**
     * 获取开服天数加成积分
     */
    private int getScoreDayAddition() {
        if (ghostData.getAvgOpenDay() == 0) {
            return 1;
        }

        // 获取积分放大系数
        int scoreLarge = 1;
        for (int i = 0; i < ghostConfig.getScoreDayList().size(); i++) {
            scoreLarge = ghostConfig.getScoreValueList().get(i);
            if (ghostData.getAvgOpenDay() < ghostConfig.getScoreDayList().get(i)) {
                break;
            }
        }

        return scoreLarge;
    }

    /**
     * 初始化boss总血量
     */
    private void initBatchBossTotalHp() {
        Map<Integer, Map<Integer, GhostBossData>> bossDataMap = ghostData.getBossMap().get(ghostData.getMaxBatchNo());
        long totalHp = 0L;
        for (Map<Integer, GhostBossData> map : bossDataMap.values()) {
            for (GhostBossData bossData : map.values()) {
                totalHp += bossData.getTotalHp();
            }
        }
        ghostData.setBatchBossTotalHp(totalHp);
    }

    public void addChestData(long serverId,String unionId,long userId, int boxId) {
        Map<String, Map<Integer, Integer>> unionChestMap = ghostData.getUnionChest();
        synchronized (unionChestMap){
            if(!unionChestMap.containsKey(unionId)){
                unionChestMap.put(unionId,new ConcurrentHashMap<>());
            }
            Map<Integer, Integer> chestIdMap = unionChestMap.get(unionId);
            chestIdMap.put(boxId,chestIdMap.getOrDefault(boxId,0) + 1);
            syncUnionNewsRedHot(unionId, serverId,userId);
            ghostData.setUnionChest(unionChestMap);
            logger.warn("玩家放弃宝箱，共享给商会{}了",unionId);
        }
    }

    public void getChestData(long serverId,long userId, String unionId) {
        GhostActivityProto.GetGhostUnionChestDataRespMsg.Builder respMsg = GhostActivityProto.GetGhostUnionChestDataRespMsg.newBuilder();
        respMsg.setRet(0);
        Map<String, Map<Integer, Integer>> unionChestMap = ghostData.getUnionChest();
        Map<Integer, Integer> chestIdMap = unionChestMap.getOrDefault(unionId,new ConcurrentHashMap<>());
        for(int boxId : chestIdMap.keySet()){
            if(chestIdMap.get(boxId) == 0)continue;
            GhostActivityProto.GhostChestInfoMsg.Builder boxInfoMsg = GhostActivityProto.GhostChestInfoMsg.newBuilder();
            boxInfoMsg.setBoxId(boxId);
            boxInfoMsg.setBoxNum(chestIdMap.get(boxId));
            respMsg.addChests(boxInfoMsg);
        }
        MessageHelper.sendPacket(serverId, userId, YanQuMessageUtils.buildMessage(ClientProtocol.U_GHOST_GET_UNION_CHEST, respMsg));
    }

    public void removeChestData(long serverId, long userId, String unionId, int boxId) {
        GhostActivityProto.CrossHandleBoxRespMsg.Builder respMsg = GhostActivityProto.CrossHandleBoxRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setBoxId(boxId);
        Map<String, Map<Integer, Integer>> unionChestMap = ghostData.getUnionChest();
        synchronized (unionChestMap){
            if(!unionChestMap.containsKey(unionId)){
                unionChestMap.put(unionId,new ConcurrentHashMap<>());
            }
            Map<Integer, Integer> chestIdMap = unionChestMap.get(unionId);
            if(chestIdMap.getOrDefault(boxId,0) > 0){
                chestIdMap.put(boxId,chestIdMap.getOrDefault(boxId,0) - 1);
                ghostData.setUnionChest(unionChestMap);
            }else{
                respMsg.setRet(GameErrorCode.E_GHOST_ACTIVITY_NO_UNION_CHEST);
            }
        }
        MessageHelper.sendPacket(serverId, userId, YanQuMessageUtils.buildMessage(GameProtocol.S_GHOST_HANDLE_BOX_EVENT_FROM_CROSS, respMsg));
    }
}